package com.shine.sys.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.shine.common.repository.hibernate.HibernateDao;
import com.shine.common.utils.BeanUtils;
import com.shine.sys.entity.Resource;
import com.shine.sys.service.ResourceService;
import com.shine.sys.web.dto.ResourceDto;


@Service
public class ResourceServiceImpl implements ResourceService {
	
	@Autowired
	private HibernateDao<Resource, Integer> basedaoResource ;

	@Override
	public void add(ResourceDto dto) {
		Resource entity = new Resource() ;
		BeanUtils.copyNotNullProperties(dto, entity);
		
		if(null != dto.getParentIdentity() && !"".equals(dto.getParentIdentity().trim())) {
			entity.setParentIdentity(dto.getParentIdentity()+":"+dto.getIdentity());
		} else {
			entity.setParentIdentity(dto.getIdentity());
		}
		Resource r = this.basedaoResource.save(entity);
		
		if("menu".equals(dto.getType()) && null != dto.getOpers() && !"".equals(dto.getOpers().trim())) {
			String[] split = dto.getOpers().split(",") ;
			for (String op : split) {
				String[] v = op.split("-") ;
				Resource opers = new Resource() ;
				opers.setParentId(r.getId());
				opers.setType("oper");
				opers.setIdentity(v[0]);
				opers.setParentIds((null != r.getParentIds()?r.getParentIds() + "/":"") + r.getId());
				opers.setParentIdentity((null!=entity.getParentIdentity()?entity.getParentIdentity()+":"+v[0] : entity.getIdentity() + ":" + v[0]));
				opers.setName(v[1]);
				this.basedaoResource.save(opers);
			}
		}
	}
	
	@Override
	public void delete(Integer id) {
		del(id);
	}
	private void del(Integer id) {
		String queryChildCount = "select t.id from sys_resource t where t.parentId=?" ;
		List<Resource> childs = this.basedaoResource.findListSQL(queryChildCount, new Object[]{id}, Resource.class, false) ;
		if(null != childs && childs.size() > 0) {
			for (Resource resource : childs) {
				del(resource.getId());
			}
		}
		this.basedaoResource.delete(Resource.class, id) ;
	}

	@Override
	public void update(ResourceDto dto) {
		Resource entity = this.basedaoResource.getEntity(Resource.class, dto.getId());
		
		if(null != dto.getParentIdentity() && !"".equals(dto.getParentIdentity().trim()) && !entity.getParentIdentity().equals(dto.getParentIdentity())) {
			dto.setParentIdentity(dto.getParentIdentity()+":"+dto.getIdentity());
		} else {
			dto.setParentIdentity(dto.getIdentity());
		}
		
		if("menu".equals(dto.getType()) && null != dto.getOpers() && !"".equals(dto.getOpers().trim())) {
			
			List<Resource> opers = getResourceByParentId(entity.getId()) ;
			
			//添加操作
			if(null == opers || opers.isEmpty()) {
				String[] split = dto.getOpers().split(",") ;
				for (String op : split) {
					String[] v = op.split("-") ;
					Resource o = new Resource() ;
					o.setParentId(entity.getId());
					o.setType("oper");
					o.setIdentity(v[0]);
					
					o.setParentIds((null != dto.getParentIds()? dto.getParentIds()+"/" : "") + entity.getId());
					o.setParentIdentity(dto.getParentIdentity() + v[0]);
					
					o.setName(v[1]);
					this.basedaoResource.save(o) ;
				}
			} else {//操作是否存在，存在则不添加
				List<String> opersAdd = new ArrayList<String>() ;
				for (Resource r : opers) {
					opersAdd.add(r.getIdentity()+"-"+r.getName()) ;
				}
				
				String[] split = dto.getOpers().split(",") ;
				for (String splitOpers : split) {
					if(!opersAdd.contains(splitOpers)) {
						String[] v = splitOpers.split("-") ;
						Resource o = new Resource() ;
						o.setParentId(entity.getId());
						o.setType("oper");
						o.setIdentity(v[0]);
						
						o.setParentIds((null != dto.getParentIds()? dto.getParentIds()+"/" : "") + entity.getId());
						o.setParentIdentity(dto.getParentIdentity() + ":" + v[0]);
						
						o.setName(v[1]);
						this.basedaoResource.save(o) ;
					}
				}
			}
			
		}
		
		BeanUtils.copyNotNullProperties(dto, entity);
		this.basedaoResource.update(entity);
	}
	private List<Resource> getResourceByParentId(Integer id) {
		String queryString = "select t.* from sys_resource t where t.type='oper' and t.parentId=?" ;
		return this.basedaoResource.findListSQL(queryString, new Object[]{id}, Resource.class, true);
	}
	
	@Override
	public ResourceDto getOne(Integer id) {
		Resource entity = this.basedaoResource.getEntity(Resource.class, id) ;
		ResourceDto dto = new ResourceDto() ;
		BeanUtils.copyNotNullProperties(entity, dto);
		
		if("menu".equals(dto.getType())) {
			StringBuffer opersStr = new StringBuffer() ;
			List<Resource> opers = getResourceByParentId(dto.getId()) ;
			for (Resource r : opers) {
				opersStr.append(r.getIdentity()+"-"+r.getName()).append(",") ;
			}
			if(!"".equals(opersStr) && opersStr.length() > 0) {
				dto.setOpers(opersStr.deleteCharAt(opersStr.length()-1).toString());
			}
		}
		
		return dto ;
		
	}

	@Override
	public List<ResourceDto> list(ResourceDto dto) {
		
		StringBuffer queryString = new StringBuffer("SELECT t.* FROM sys_resource t WHERE 1=1") ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		queryString = addWhere(queryString, alias, dto) ;
		
		return this.basedaoResource.findListSQL(queryString.toString(), alias, ResourceDto.class, false) ;
	}
	
	
	private StringBuffer addWhere(StringBuffer queryString, Map<String, Object> alias, ResourceDto dto) {
		if(null != dto) {
			if(null != dto.getId()) {
				queryString.append(" AND t.id=:id") ;
				alias.put("id", dto.getId()) ;
			}
		}
		return queryString;
	}

	@Override
	public List<ResourceDto> tree(ResourceDto dto) {
		String queryString = "select t.* from sys_resource t where 1=1 " ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		if(null != dto && dto.getId() != null) {
			queryString += " and t.parentId=:parentId" ;
			alias.put("parentId", dto.getId()) ;
		} else {
			queryString += " and t.parentId is null" ;
		}
		
		List<ResourceDto> resources = this.basedaoResource.findListSQL(queryString, alias, ResourceDto.class, false) ;
		
		return convertToMenus(resources) ;
	}
	
	private List<ResourceDto> convertToMenus(List<ResourceDto> resources) {
		List<ResourceDto> menus = new ArrayList<ResourceDto>() ;
		
		for (ResourceDto resource : resources) {
			menus.add(recursiveResource(resource)) ;
		}
		return menus ;
	}
	
	private ResourceDto recursiveResource(ResourceDto dto) {
		String queryChild = "select t.* from sys_resource t where t.parentId=?" ;
		List<ResourceDto> childs = this.basedaoResource.findListSQL(queryChild, new Object[]{dto.getId()}, ResourceDto.class, false) ;
		
		if(null != childs && !childs.isEmpty()) {
			List<ResourceDto> children = new ArrayList<ResourceDto>() ;
			for (ResourceDto child : childs) {
				children.add(recursiveResource(child)) ;
			}
			dto.setChildren(children);
		}
		return dto;
	}

	public List<ResourceDto> allotPermiss(ResourceDto dto) {
		String queryString = "select t.* from sys_resource t where 1=1 " ;
		
		Map<String, Object> alias = new HashMap<String, Object>() ;
		if(null != dto && dto.getId() != null) {
			queryString += " and t.parentId=:parentId" ;
			alias.put("parentId", dto.getId()) ;
		} else {
			queryString += " and t.parentId is null" ;
		}
		
		List<ResourceDto> resources = this.basedaoResource.findListSQL(queryString, alias, ResourceDto.class, false) ;
		
		return convertToOperation(resources) ;
	}
	private List<ResourceDto> convertToOperation(List<ResourceDto> resources) {
		List<ResourceDto> menus = new ArrayList<ResourceDto>() ;
		
		for (ResourceDto resource : resources) {
			menus.add(recursiveResourceOPerations(resource)) ;
		}
		
		return menus ;
	}
	
	private ResourceDto recursiveResourceOPerations(ResourceDto dto) {
		String queryChild = "select t.* from sys_resource t where t.parentId=?" ;
		List<ResourceDto> childs = this.basedaoResource.findListSQL(queryChild, new Object[]{dto.getId()}, ResourceDto.class, false) ;
		
		if(null != childs && !childs.isEmpty()) {
			List<ResourceDto> children = new ArrayList<ResourceDto>() ;
			List<ResourceDto> opers = new ArrayList<ResourceDto>() ;
			
			for (ResourceDto child : childs) {
				if("oper".equals(child.getType())) {
					opers.add(child) ;
				} else {
					children.add(recursiveResourceOPerations(child)) ;
				}
				
			}
			dto.setOperations(opers);
			dto.setChildren(children);
		}
		return dto;
	}

	
}
